/*
 * Copyright(c) 2015 Reconova Information Technologies Co., Ltd. All rights reserved.
 *
 * 通过V4L2获取视频帧以及用H264硬编码视频帧的C接口。
 *
 * Created by Cyberman Wu on Jun 12th, 2015.
 *
 *
 * 增加只取灰度图的接口。
 * Modified by Cyberman Wu on Sep 2nd, 2015.
 *
 *
 * 1. 原来取视频帧的接口由自动进行H.264编码改为用一个参数来控制是否进行编码。
 *    这个是为了解决我们准备丢掉一些帧来录相，而编码时P帧也可以是参考帧，只
 *    简单丢掉编码后的一帧会导致视频质量下降。
 * 2. 添加Zero Copy接口；添加对Zero Copy返回显式H.264编码的接口。注意ZC接口
 *     不会自动做编码，也不会录相。
 * Modified by Cyberman Wu on Sep 29th, 2015.
 *
 *
 *
 * 增加Gamma Correction打开和关闭的接口。
 *
 * Modified by Cyberman Wu on Dec 12th, 2015.
 *
 */

#ifndef __CAPTURE_H__
#define __CAPTURE_H__

#ifdef __cplusplus
extern "C" {
#endif

#include "cap_types.h"


/*
 * 配置初始化时向驱动申请的buffer的个数。注意这个只是一个期望值，实际上有
 * 可能因为空间不够而实际分配的少；或因为驱动的原因比这个值大。
 * 这个函数需要在VideoCapture_Initialize()之前调用，如果不配置的话，初始
 * 化会使用缺省值。
 *
 * ==== 用VideoCapture_PreConfig....()的函数名都是需要在实始化之前调用的，
 * ==== 配置一些参数不使用缺省值。这个本来可以直接做为初始化的参数，但这样
 * ==== 就需要修改接口了，不利于原来程序的兼容。
 * ++++ 目前我们不支持多实例，一个实例对应一个摄像头；如果后面要支持的话，
 * ++++ 这个接口有可能会合并到初始化中，或者采用预分配句柄的方式。
 *
 * 参数说明：
 *   count          -- 希望分配的驱动buffer个数。目前在全志的R16上测试，
 *                     发现驱动分配最少为3个，请求1、2都是分配3个；而再大
 *                     一直到14都是分配到申请的个数。再大的话申请会成功，
 *                     但mmap()失败（物理内存不够？），再加上疑似驱动问题，
 *                     这个地方失败直接返回，后面这个摄像头会一直busy，
 *                     只能重新启动系统。
 *                     似乎是驱动中少了buffer上限的判断处理。
 * 返回值：
 *   0表示成功，小于0失败。
 */
int VideoCapture_PreConfigBufCnt(uint32_t count);


/*
 * 初始化抓视频帧的功能。
 *
 * 参数说明：
 *   dev_id         -- V4L2使用的设备是/dev/video<N>，这个dev_id对应<N>。
 *   width          -- 视频的宽度。
 *   height         -- 视频的高度。
 *   pixel_fmt      -- 视频频的格式。目前只支持NV12和NV21。
 *   frame_rate     -- 帧率。目前测试在CSI摄像头上似乎不起作用，传入<=0的值
 *                     使用缺省帧率。
 *   reverse        -- 把图像旋转180度。0表示不翻转，1表示翻转。要使用图像
 *                     翻转功能，需要width是16的倍数。
 *
 * 返回值：
 *   0表示成功，小于0失败。
 */
int VideoCapture_Initialize(int dev_id, int width, int height, 
                            int pixel_fmt, int frame_rate, 
                            int reverse);

/*
 * 结束抓视频帧的功能，释放相关的资源。
 *
 * 返回值：
 *   0表示成功，小于0失败。
 */
int VideoCapture_Finalize(void);

/*
 * 初始化成功之后并不会有视频被抓上来，需要再调用这个接口使能驱动的抓包。
 *
 * 返回值：
 *   0表示成功，小于0失败。
 *
 * Warning!!!
 *   目前从测试结果看，如果初始化成功之后没有调用这个接口，退出进程再打开
 *   V4L2抓视频会出现Busy的错误，怀疑和全志的驱动有关系，至少从V4L2的官方
 *   文档看不应该这样，只是还没有时间去仔细确认。
 *   出现这种问题之后，目前还没有找到好的解决办法，只能重启系统。
 *   后面考虑在初始化之后自动使能抓包？
 */
int VideoCapture_Start(void);

/*
 * 不使用之后可以直接Finalize，不一定非要Stop。我们单独提供是想看在不需要
 * 抓视频的时候，如果Stop视频的capture是否能节省一些系统资源。
 *
 * 返回值：
 *   0表示成功，小于0失败。
 */
int VideoCapture_Stop(void);

/*
 * 抓取一帧视频（根据参数会自动做H.264编码）。把H.264编码合在这个接口中
 * 是考虑到H.264编码等待时间刚好可以做数据拷贝的操作，以提高情况；而H264
 * 编码后的数据最比较小，再拷贝出来对性能影响比较小。
 * 本来我们设计为分开两个接口是考虑到有可能只做内部录相而不取出来；对于
 * 取H.264出来的情况直接传一个buffer到这个接口性能略高一些。
 *
 * 参数说明：
 *   pBuf       - 参见cap_types.h中关于数据结构的说明。
 *   encode     - 这帧是否进行H.264编码，0表示不编码，非0表示编码。
 *
 * 返回值：
 *   0表示成功，小于0失败。
 */
int VideoCapture_GetFrame(S_VCBuf *pBuf, int encode);


/*
 * 抓取一帧灰度图。和VideoCapture_GetFrame()功能相似，就是只把数据中的Y
 * 部分拷贝出来，以减少数据拷贝的CPU消耗。只用灰度图情况下可以考虑用这个
 * 接口。
 *
 * 参数说明：
 *   pBuf       - 参见cap_types.h中关于数据结构的说明。
 *   encode     - 这帧是否进行H.264编码，0表示不编码，非0表示编码。编码
 *                用的是全图，包含UV部分。
 *
 * 返回值：
 *   0表示成功，小于0失败。
 */
int VideoCapture_GetGrayImage(S_VCBuf *pBuf, int encode);



/**************************************************************
 * 在单核的V3s上测试，发现拷贝数据还是消耗了很多CPU的，所以实现
 * 零拷贝的接口。这在全志的平台上应该是可行的，因为我们前面测试
 * H264编码时发现它里面V4L2驱动映射上来的Buffer是cacheable的，
 * 但用于其它平台的话，还需要想办法再测试一下。
 * 我们的算法会大规模访问数据，在前面的FPGA项目中发现如果数据用
 * uncacheable，算法的性能会急剧下降。
 *
 * 使用Zero Copy接口获取到的视频帧尽量不要在外部缓存，用完之后
 * 要及时释放。
 *************************************************************/
/*
 * 以Zero Copy的方式获取一个视频帧。注意：这个接口不会自动产生
 * H.264编码的帧，如果要编码需要用VideoCapture_H264EncZCFrame()
 * 接口显式的编码。
 *
 * 参数说明：
 *   参见cap_types.h中关于数据结构的说明。
 *
 * 返回值：
 *   0表示成功，小于0失败。
 */
int VideoCapture_GetZCFrame(S_VCZCBuf *pBuf);
/*
 * 释放Zero Copy的视频帧。
 *
 * 参数说明：
 *   参见cap_types.h中关于数据结构的说明。
 *
 * 返回值：
 *   0表示成功，小于0失败。
 */
int VideoCapture_ReleaseZCFrame(S_VCZCBuf *pBuf);




/*
 * 编码是和V4L2 Capture集成到一起的，这个函数使能H.264硬编码库，设置相关的
 * 参数。原始图像的大小是在发起V4L2 Video Capture的时候指定的。
 *
 * 参数说明：
 *   width      -- 编码后图像的宽度。
 *   height     -- 编码后图像的高度。
 *   profile    -- H.264编码的Profile，目前支持三种：Baseline、Main、High。
 *                 同样的码率的话，Baseline->Main->High，质量越来越好；或者
 *                 同样的图像质量，Baseline->Main->High码率越来越小。
 *                 硬编码库这三种Profile性能差不多，但如果用软件解码，则计算
 *                 量Baseline->Main->High越来越大（同码率）。
 *   bit_rate   -- 编码后的平均码率，以bit计。
 *   fname      -- 录相文件名称。传入空指针表示不进行录相。
 *
 * 返回值：
 *   0表示成功，小于0失败。
 */
int VideoCapture_H264EncStart(int width, int height, int profile, int bit_rate, 
                              const char *fname);
/*
 * 关闭H.264硬编码库，释放相关的资源。
 *
 * 返回值：
 *   0表示成功，小于0失败。
 */
int VideoCapture_H264EncStop(void);
/*
 * 取编码后的视频帧。打开H.264编码功能之后，每调用VideoCapture_GetFrame()
 * 抓一帧视频，同时对这帧初步进行编码缓存，调用这个函数可以取得缓存的编码帧。
 *
 * 参数说明：
 *   参见cap_types.h中关于数据结构的说明。
 *
 * 返回值：
 *   0表示成功，小于0失败。
 */
int VideoCapture_H264GetEncFrame(S_H264EncBuf *pBuf);

/*
 * 编码用VideoCapture_GetZCFrame()到的帧并输出编码后的数据。注意这个必须使用
 * Zero Copy接口获取到的帧（未释放）。
 * 由于硬编码器用的是物理地址，而目前全志驱动中用的是cacheable映射到进程地址
 * 空间的（否则我们也不会开放ZC接口），所以不要试图修改数据再编码，因为修改
 * 有可能还在CPU cache中（硬编码器直接访问物理内存），所以修改很有可能不生效
 * 或部分不生效。目前ARM平台上现有的刷新Cache的机制，需要自己来开发。
 *
 * 注意：这个接口必须在VideoCapture_H264EncStart()成功之后才能使用，否则返回
 *       失败。
 *
 * 参数说明：
 *   pFrame     - 零拷贝的帧信息。
 *   pBuf       - 输出编码后的视频数据及相关信息。
 * 参数具体类型的详细说明参见cap_types.h。
 *
 * 返回值：
 *   0表示成功，小于0失败。
 */
int VideoCapture_H264EncZCFrame(S_VCZCBuf *pFrame, S_H264EncBuf *pBuf);

/*
 * 这此先不提供了，可以在外部直接实现。
 */
#if 0
// 这个数据只在第一帧时生成，我们允许单独获取这个信息。这样更灵活一些。
int VideoCapture_H264GetKeyInfo(S_H264EncBuf *pBuf);
// 这个接口不会自动对关键帧前面增加SPS等信息。对于带宽很小的情况下，这个
// 还是可以略微省掉一些信息的。
int VideoCapture_H264GetRawFrame(S_H264EncBuf *pBuf);
#endif



/*
 * 设置之后，图像会先进行Gamma Correction，目前只对灰度部分进行调整（也就是
 * 只调整亮度）。
 * 目前这个接口只影响用VideoCapture_GetFrame()和VideoCapture_GetGrayImage()
 * 获取的图像，Zero Copy接口不受影响。之所以这样设置，是因为Zero Copy的原始
 * 数据修改之后，再调用编码接口会有Cache未刷新的问题，所以就不支持它了。
 */
int VideoCapture_GammaCorrectionEnable(float gamma);
/*
 * 停止对图像进行Gamma Correction。
 */
int VideoCapture_GammaCorrectionDisable(void);



#ifdef __cplusplus
}
#endif

#endif // __CAPTURE_H__

